home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / jade / src / refresh.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  10KB  |  409 lines

  1. /* refresh.c -- Working out what to redraw in a window
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING.    If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. _PR void refresh_init(void);
  24. _PR void refresh_window(VW *);
  25. _PR void flag_insertion(TX *, POS *, POS *);
  26. _PR void flag_deletion(TX *, POS *, POS *);
  27. _PR void flag_modification(TX *, POS *, POS *);
  28. _PR void refresh_world(void);
  29. _PR void refresh_world_curs(void);
  30.  
  31. _PR VALUE cmd_cursor(VALUE status);
  32. DEFUN("cursor", cmd_cursor, subr_cursor, (VALUE status), V_Subr1, DOC_cursor) /*
  33. ::doc:cursor::
  34. cursor STATUS
  35.  
  36. Turns cursor on or off, normally cursor is always off when an event is being
  37. evaluated.
  38. ::end:: */
  39. {
  40.     cursor(curr_vw, NILP(status) ? CURS_OFF : CURS_ON);
  41.     return(sym_t);
  42. }
  43.  
  44. _PR VALUE cmd_refresh_all(void);
  45. DEFUN_INT("refresh-all", cmd_refresh_all, subr_refresh_all, (void), V_Subr0, DOC_refresh_all, "") /*
  46. ::doc:refresh_all::
  47. refresh-all
  48.  
  49. Redraw anything that has been changed since the last refresh.
  50. ::end:: */
  51. {
  52.     refresh_world();
  53.     return(sym_t);
  54. }
  55.  
  56. void
  57. refresh_init(void)
  58. {
  59.     ADD_SUBR(subr_cursor);
  60.     ADD_SUBR(subr_refresh_all);
  61. }
  62.  
  63. /*
  64.  * If no changes have been made to the buffer, call this to do any vertical
  65.  * scrolling. Returns 0 if nothing happened, 1 if it scrolled a bit, 2
  66.  * if it redrew the whole window.
  67.  */
  68. static int
  69. vert_scroll(VW *vw)
  70. {
  71.     long y = vw->vw_StartLine - vw->vw_LastDisplayOrigin.pos_Line;
  72.     if(y < 0)
  73.     {
  74.     if(-y > vw->vw_MaxScroll)
  75.     {
  76.         redraw_all(vw);
  77.         return(2);
  78.     }
  79.     else
  80.     {
  81.         sys_scroll_vw(vw, y);
  82.         redraw_lines(vw, vw->vw_StartLine,
  83.              vw->vw_LastDisplayOrigin.pos_Line);
  84.         return(1);
  85.     }
  86.     }
  87.     else if(y > 0)
  88.     {
  89.     if(y > vw->vw_MaxScroll)
  90.     {
  91.         redraw_all(vw);
  92.         return(2);
  93.     }
  94.     else
  95.     {
  96.         sys_scroll_vw(vw, y);
  97.         redraw_lines(vw, vw->vw_StartLine + vw->vw_MaxY - y,
  98.              vw->vw_StartLine + vw->vw_MaxY);
  99.         return(1);
  100.     }
  101.     }
  102.     return(0);
  103. }
  104.  
  105. /*
  106.  * Refreshes one window.
  107.  */
  108. void
  109. refresh_window(VW *vw)
  110. {
  111.     TX *tx = vw->vw_Tx;
  112.     if(vw && vw->vw_Window && (!vw->vw_DeferRefresh))
  113.     {
  114.     if((vw->vw_Flags & VWFF_SLEEPING) == 0)
  115.     {
  116.         if((vw->vw_Flags & VWFF_REFRESH_STATUS)
  117.            || (vw->vw_Flags & VWFF_FORCE_REFRESH)) /* implies msg */
  118.         {
  119.         refresh_message(vw);
  120.         vw->vw_Flags &= ~VWFF_REFRESH_STATUS;
  121.         }
  122.         resync_xy(vw);
  123.         if((vw->vw_LastRefTx != vw->vw_Tx)
  124.            || (vw->vw_Flags & VWFF_FORCE_REFRESH)
  125.            || (tx->tx_Flags & TXFF_REFRESH_ALL))
  126.         {
  127.         if(vw->vw_Flags & VWFF_FORCE_REFRESH)
  128.             /* draw the line as well. */
  129.             draw_message_line(vw);
  130.         redraw_all(vw);
  131.         vw->vw_Flags &= ~(VWFF_FORCE_REFRESH | VWFF_REFRESH_BLOCK);
  132.         tx->tx_Flags &= ~TXFF_REFRESH_ALL;
  133.         }
  134.         else if(tx->tx_Changes == tx->tx_LastChanges)
  135.         {
  136.         vert_scroll(vw);
  137.         if(vw->vw_Flags & VWFF_REFRESH_BLOCK)
  138.         {
  139.             redraw_lines_clr(vw, vw->vw_BlockS.pos_Line,
  140.                      vw->vw_BlockE.pos_Line);
  141.             vw->vw_Flags &= ~VWFF_REFRESH_BLOCK;
  142.         }
  143.         }
  144.         else
  145.         {
  146.         long endline = vw->vw_StartLine + vw->vw_MaxY;
  147.         int vscrl;
  148.         /* check if modified region hits window */
  149.         if((vw->vw_StartLine > tx->tx_ModEnd.pos_Line)
  150.            || (endline <= tx->tx_ModStart.pos_Line))
  151.         {
  152.             /* nope. just do any easy scrolling. */
  153.             vert_scroll(vw);
  154.             if(vw->vw_Flags & VWFF_REFRESH_BLOCK)
  155.             {
  156.             redraw_lines_clr(vw, vw->vw_BlockS.pos_Line,
  157.                      vw->vw_BlockE.pos_Line);
  158.             vw->vw_Flags &= ~VWFF_REFRESH_BLOCK;
  159.             }
  160.         }
  161.         else if((vscrl = vert_scroll(vw)) != 2)
  162.         {
  163.             /* is modified region just one line? */
  164.             if((tx->tx_ModStart.pos_Line == tx->tx_ModEnd.pos_Line)
  165.                && (tx->tx_ModDelta == 0))
  166.             {
  167.             if(vw->vw_Flags & VWFF_REFRESH_BLOCK)
  168.             {
  169.                 redraw_lines_clr(vw, vw->vw_BlockS.pos_Line,
  170.                          vw->vw_BlockE.pos_Line);
  171.                 if((tx->tx_ModStart.pos_Line < vw->vw_BlockS.pos_Line)
  172.                    || (tx->tx_ModStart.pos_Line > vw->vw_BlockE.pos_Line))
  173.                 redraw_line_from(vw, tx->tx_ModStart.pos_Col,
  174.                          tx->tx_ModStart.pos_Line);
  175.                 vw->vw_Flags &= ~VWFF_REFRESH_BLOCK;
  176.             }
  177.             else
  178.                 redraw_line_from(vw, tx->tx_ModStart.pos_Col,
  179.                          tx->tx_ModStart.pos_Line);
  180.             }
  181.             else if(tx->tx_ModDelta == 0)
  182.             {
  183.             /* not able to do any pasting */
  184.             redraw_region(vw, &tx->tx_ModStart, &tx->tx_ModEnd);
  185.             if(vw->vw_Flags & VWFF_REFRESH_BLOCK)
  186.             {
  187.                 if(!(POS_LESS_P(&vw->vw_BlockE, &tx->tx_ModEnd)
  188.                  && POS_GREATER_P(&vw->vw_BlockS, &tx->tx_ModStart)))
  189.                 redraw_lines_clr(vw, vw->vw_BlockS.pos_Line,
  190.                          vw->vw_BlockE.pos_Line);
  191.                 vw->vw_Flags &= ~VWFF_REFRESH_BLOCK;
  192.             }
  193.             }
  194.             else if(tx->tx_ModDelta > 0)
  195.             {
  196.             /* lines have been added: move down the lines they
  197.                displaced. */
  198.             if(vscrl == 0)
  199.                 cut_paste_lines(vw, tx->tx_ModStart.pos_Line + 1,
  200.                         tx->tx_ModStart.pos_Line + tx->tx_ModDelta + 1);
  201.             redraw_region(vw, &tx->tx_ModStart, &tx->tx_ModEnd);
  202.             if(vw->vw_Flags & VWFF_REFRESH_BLOCK)
  203.             {
  204.                 if(!(POS_LESS_P(&vw->vw_BlockE, &tx->tx_ModEnd)
  205.                  && POS_GREATER_P(&vw->vw_BlockS, &tx->tx_ModStart)))
  206.                 redraw_lines_clr(vw, vw->vw_BlockS.pos_Line,
  207.                          vw->vw_BlockE.pos_Line);
  208.                 vw->vw_Flags &= ~VWFF_REFRESH_BLOCK;
  209.             }
  210.             }
  211.             else if(tx->tx_ModDelta < 0)
  212.             {
  213.             /* lines deleted. */
  214.             POS line_end;
  215.             if(vscrl == 0)
  216.             {
  217. #if 1
  218.                 if(tx->tx_ModStart.pos_Col == 0)
  219.                 cut_paste_lines(vw, tx->tx_ModEnd.pos_Line - tx->tx_ModDelta,
  220.                         tx->tx_ModEnd.pos_Line);
  221.                 else
  222.                 cut_paste_lines(vw, tx->tx_ModEnd.pos_Line - tx->tx_ModDelta + 1,
  223.                         tx->tx_ModEnd.pos_Line + 1);
  224. #else
  225.                 if(tx->tx_ModStart.pos_Col == 0)
  226.                 cut_paste_lines(vw, tx->tx_ModEnd.pos_Line,
  227.                         tx->tx_ModEnd.pos_Line + tx->tx_ModDelta);
  228.                 else
  229.                 cut_paste_lines(vw, tx->tx_ModEnd.pos_Line + 1,
  230.                         tx->tx_ModEnd.pos_Line + tx->tx_ModDelta + 1);
  231. #endif
  232.             }
  233.             line_end.pos_Line = tx->tx_ModStart.pos_Line;
  234.             line_end.pos_Col = tx->tx_Lines[line_end.pos_Line].ln_Strlen - 1;
  235.             redraw_region(vw, &tx->tx_ModStart,
  236.                       POS_LESS_P(&tx->tx_ModEnd, &line_end)
  237.                       ? &line_end
  238.                       : &tx->tx_ModEnd);
  239.             if(vw->vw_Flags & VWFF_REFRESH_BLOCK)
  240.             {
  241.                 if(!(POS_LESS_P(&vw->vw_BlockE, &tx->tx_ModEnd)
  242.                  && POS_GREATER_P(&vw->vw_BlockS, &tx->tx_ModStart)))
  243.                 redraw_lines_clr(vw, vw->vw_BlockS.pos_Line,
  244.                          vw->vw_BlockE.pos_Line);
  245.                 vw->vw_Flags &= ~VWFF_REFRESH_BLOCK;
  246.             }
  247.             }
  248.         }
  249.         }
  250.         vw->vw_LastRefTx = tx;
  251.         vw->vw_LastDisplayOrigin = vw->vw_DisplayOrigin;
  252.     }
  253.     else
  254.         vw->vw_Flags |= VWFF_FORCE_REFRESH;
  255.     }
  256.     else if(vw)
  257.     {
  258.     if(!(--vw->vw_DeferRefresh))
  259.         vw->vw_Flags |= VWFF_FORCE_REFRESH;
  260.     }
  261. }
  262.  
  263. /*
  264.  * Notes that buffer TX has had text added between START and END.
  265.  */
  266. void
  267. flag_insertion(TX *tx, POS *start, POS *end)
  268. {
  269.     if(tx->tx_LastChanges == tx->tx_Changes)
  270.     {
  271.     /* first insertion */
  272.     tx->tx_ModStart = *start;
  273.     tx->tx_ModEnd = *end;
  274.     tx->tx_ModDelta = end->pos_Line - start->pos_Line;
  275.     }
  276.     else
  277.     {
  278.     if(POS_LESS_P(start, &tx->tx_ModStart))
  279.         tx->tx_ModStart = *start;
  280.     if(POS_GREATER_P(end, &tx->tx_ModEnd))
  281.         tx->tx_ModEnd = *end;
  282.     tx->tx_ModDelta += end->pos_Line - start->pos_Line;
  283.     }
  284.     tx->tx_Changes++;
  285. }
  286.  
  287. /*
  288.  * Same for deleted areas.
  289.  */
  290. void
  291. flag_deletion(TX *tx, POS *start, POS *end)
  292. {
  293.     if(tx->tx_LastChanges == tx->tx_Changes)
  294.     {
  295.     /* first */
  296.     tx->tx_ModStart = *start;
  297. #if 1
  298.     tx->tx_ModEnd = *start;
  299. #else
  300.     tx->tx_ModEnd = *end;
  301. #endif
  302.     tx->tx_ModDelta = -(end->pos_Line - start->pos_Line);
  303.     }
  304.     else
  305.     {
  306.     if(POS_LESS_P(start, &tx->tx_ModStart))
  307.         tx->tx_ModStart = *start;
  308. #if 1
  309.     if(POS_GREATER_P(start, &tx->tx_ModEnd))
  310.         tx->tx_ModEnd = *start;
  311. #else
  312.     if(POS_GREATER_P(end, &tx->tx_ModEnd))
  313.         tx->tx_ModEnd = *end;
  314. #endif
  315.     tx->tx_ModDelta -= end->pos_Line - start->pos_Line;
  316.     }
  317.     tx->tx_Changes++;
  318. }
  319.  
  320. /*
  321.  * Means that there is still the same layout of text between START and END,
  322.  * but some of the character values may have been modified.
  323.  */
  324. void
  325. flag_modification(TX *tx, POS *start, POS *end)
  326. {
  327.     if(tx->tx_LastChanges == tx->tx_Changes)
  328.     {
  329.     /* first */
  330.     tx->tx_ModStart = *start;
  331.     tx->tx_ModEnd = *end;
  332.     tx->tx_ModDelta = 0;
  333.     }
  334.     else
  335.     {
  336.     if(POS_LESS_P(start, &tx->tx_ModStart))
  337.         tx->tx_ModStart = *start;
  338.     if(POS_GREATER_P(end, &tx->tx_ModEnd))
  339.         tx->tx_ModEnd = *end;
  340.     }
  341.     tx->tx_Changes++;
  342. }
  343.  
  344. /*
  345.  * Refeshes everything that should be.
  346.  */
  347. void
  348. refresh_world(void)
  349. {
  350.     VW *vw;
  351.     TX *tx;
  352.     for(vw = view_chain; vw; vw = vw->vw_Next)
  353.     {
  354.     if(vw->vw_Window)
  355.         refresh_window(vw);
  356.     }
  357.     tx = buffer_chain;
  358.     while(tx)
  359.     {
  360.     tx->tx_LastChanges = tx->tx_Changes;
  361.     tx = tx->tx_Next;
  362.     }
  363. }
  364.  
  365. /*
  366.  * Same as the above but assumes that the cursor is currently drawn.
  367.  */
  368. void
  369. refresh_world_curs(void)
  370. {
  371.     VW *vw;
  372.     TX *tx;
  373.     for(vw = view_chain; vw; vw = vw->vw_Next)
  374.     {
  375.     if(vw->vw_Window
  376. #if 0
  377.        && ((vw->vw_Tx != vw->vw_LastRefTx)
  378.            || (vw->vw_Tx->tx_Changes != vw->vw_Tx->tx_LastChanges)
  379.            || (vw->vw_Flags & (VWFF_FORCE_REFRESH | VWFF_REFRESH_BLOCK
  380.                    | VWFF_REFRESH_STATUS)))
  381. #endif
  382.        )
  383.     {
  384.         if(vw == curr_vw)
  385.         cursor(vw, CURS_OFF);
  386.         refresh_window(vw);
  387.         if(vw == curr_vw)
  388.         cursor(vw, CURS_ON);
  389.     }
  390. #if 0
  391.     else if(vw->vw_Window && (vw->vw_Flags & VWFF_REFRESH_STATUS))
  392.     {
  393.         if(vw == curr_vw)
  394.         cursor(vw, CURS_OFF);
  395.         refresh_message(vw);
  396.         vw->vw_Flags &= ~VWFF_REFRESH_STATUS;
  397.         if(vw == curr_vw)
  398.         cursor(vw, CURS_ON);
  399.     }
  400. #endif
  401.     }
  402.     tx = buffer_chain;
  403.     while(tx)
  404.     {
  405.     tx->tx_LastChanges = tx->tx_Changes;
  406.     tx = tx->tx_Next;
  407.     }
  408. }
  409.